#region Copyright (c) 2000-2011 Developer Express Inc.
/*
{*******************************************************************}
{                                                                   }
{       Developer Express .NET Component Library                    }
{                                                                   }
{                                                                   }
{       Copyright (c) 2000-2011 Developer Express Inc.              }
{       ALL RIGHTS RESERVED                                         }
{                                                                   }
{   The entire contents of this file is protected by U.S. and       }
{   International Copyright Laws. Unauthorized reproduction,        }
{   reverse-engineering, and distribution of all or any portion of  }
{   the code contained in this file is strictly prohibited and may  }
{   result in severe civil and criminal penalties and will be       }
{   prosecuted to the maximum extent possible under the law.        }
{                                                                   }
{   RESTRICTIONS                                                    }
{                                                                   }
{   THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES           }
{   ARE CONFIDENTIAL AND PROPRIETARY TRADE                          }
{   SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS   }
{   LICENSED TO DISTRIBUTE THE PRODUCT AND ALL ACCOMPANYING .NET    }
{   CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY.                 }
{                                                                   }
{   THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED      }
{   FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE        }
{   COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE       }
{   AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT  }
{   AND PERMISSION FROM DEVELOPER EXPRESS INC.                      }
{                                                                   }
{   CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON       }
{   ADDITIONAL RESTRICTIONS.                                        }
{                                                                   }
{*******************************************************************}
*/
#endregion Copyright (c) 2000-2010 Developer Express Inc.

namespace DevExpress.OAuth.Web.Authentication {
    using System;
    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Json;
    using System.IO;
    using System.Text;

    [Serializable]
    [DataContract]
    public struct MixedAuthenticationTicket : IEquatable<MixedAuthenticationTicket> {        
        public static readonly MixedAuthenticationTicket Empty = new MixedAuthenticationTicket();

        public MixedAuthenticationTicket(
            string authenticationType, 
            string identity,
            string email /* optional  */,
            Nullable<Guid> principal /* optional  */,
            string fullName /* optional  */,
            string pictureUrl /* optional  */) {
            
            if (string.IsNullOrEmpty(authenticationType)) throw new ArgumentNullException("authenticationType");
            if (string.IsNullOrEmpty(identity)) throw new ArgumentNullException("identity");
            
            _AuthenticationType = authenticationType;
            _Principal = principal;
            _Identity = identity;
            _Email = email;
            _FullName = fullName;
            _PictureUrl = pictureUrl;
        }

        public string ToJson() {
            using (Stream stream = new MemoryStream()) {
                using (StreamReader reader = new StreamReader(stream)) {
                    new DataContractJsonSerializer(typeof(MixedAuthenticationTicket)).WriteObject(stream, this);
                    stream.Position = 0;
                    return reader.ReadToEnd();
                }
            }
        }

        public static MixedAuthenticationTicket FromJson(string json) {
            if (String.IsNullOrEmpty(json)) return Empty;
            try {
                using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(json))) {
                    return (MixedAuthenticationTicket)new DataContractJsonSerializer(typeof(MixedAuthenticationTicket)).ReadObject(stream);
                }
            } catch {
                return Empty;
            }
        }

        public bool IsAuthenticated {
            get {
                return (!String.IsNullOrEmpty(AuthenticationType)) &&
                    !String.IsNullOrEmpty(Identity);
            }
        }

        string _AuthenticationType;
        [DataMember]
        public string AuthenticationType {
            get {
                return _AuthenticationType;
            }
            set {
                _AuthenticationType = value;
            }
        }

        string _Identity;
        [DataMember]
        public string Identity {
            get {
                return _Identity;
            }
            set {
                _Identity = value; 
            }
        }

        Nullable<Guid> _Principal;
        [DataMember]
        public Nullable<Guid> Principal {
            get {
                return _Principal;
            }
            set {
                _Principal = value;
            }
        }

        string _FullName;
        [DataMember]
        public string FullName {
            get { 
                return _FullName; 
            }
            set { 
                _FullName = value; 
            }
        }

        string _Email;
        [DataMember]
        public string Email {
            get {
                return _Email;
            }
            set {
                _Email = value;
            }
        }

        string _PictureUrl;
        [DataMember]
        public string PictureUrl {
            get {
                return _PictureUrl;
            }
            set {
                _PictureUrl = value;
            }
        }

        public bool Equals(MixedAuthenticationTicket other) {
            return
                (String.Equals(other.AuthenticationType, this.AuthenticationType, StringComparison.Ordinal) &&
                String.Equals(other.Email, this.Email, StringComparison.Ordinal) &&
                String.Equals(other.Identity, this.Identity, StringComparison.Ordinal) &&
                String.Equals(other.PictureUrl, this.PictureUrl, StringComparison.Ordinal) &&
                (other.Principal == this.Principal) &&
                (String.Equals(other.FullName, this.FullName, StringComparison.Ordinal)));
        }

        public override bool Equals(object obj) {
            if (obj == null) {
                return Equals(Empty);
            }
            return Equals((MixedAuthenticationTicket)obj);
        }

        public override int GetHashCode() {
            // This is a hashcode is used for dictionaries etc... Include everything!
            return
                (String.IsNullOrEmpty(this.AuthenticationType) ? 0 : this.AuthenticationType.GetHashCode()) ^
                (String.IsNullOrEmpty(this.Identity) ? 0 : this.Identity.GetHashCode()) ^
                (String.IsNullOrEmpty(this.Email) ? 0 : this.Email.GetHashCode()) ^
                (String.IsNullOrEmpty(this.FullName) ? 0 : this.FullName.GetHashCode()) ^
                (String.IsNullOrEmpty(this.PictureUrl) ? 0 : this.PictureUrl.GetHashCode()) ^
                (!this.Principal.HasValue ? 0 : this.Principal.Value.GetHashCode()) ^
                (IsAuthenticated.GetHashCode());
        }

        public string GetHashCode(string identitySecret) {

            // Only include fields that are static to an identity.
            //
            // For example for OAuth... 
            //      a token might expire; 
            //      a user might change the spelling on the name;
 
            if (String.IsNullOrEmpty(identitySecret)) { throw new ArgumentNullException("identitySecret"); }
            if (String.IsNullOrEmpty(Identity)) { throw new InvalidOperationException("Ticket is not authenticated."); }
            if (String.IsNullOrEmpty(AuthenticationType)) { throw new InvalidOperationException("Ticket is not authenticated."); }
            
            using (System.Security.Cryptography.HMACSHA1 hash
                        = new System.Security.Cryptography.HMACSHA1(Encoding.ASCII.GetBytes(identitySecret))) {
                
                return Convert.ToBase64String(
                    hash.ComputeHash(Encoding.ASCII.GetBytes(
                        this.AuthenticationType.ToLowerInvariant() +
                        this.Identity.ToLowerInvariant())));
            }

        }

    }
}